import React, { useMemo, useState } from "react";
import { UserApp, UserAppDetail } from "../../../serve/interface";
import { Button, Dropdown, Input, message, Popconfirm, Progress, Spin, Tooltip, Tree, TreeProps, Typography, Upload } from "antd";
import { CaretDownOutlined, MoreOutlined, PlusOutlined, UploadOutlined } from "@ant-design/icons";
import { mapTreeData, searchTreeData } from "../../utils/mapTreeData";
import { NavigateFunction } from "react-router";
import { ModalTreeNode } from "./ModalTreeNode";
import { api_import, apis } from "../../apis";
import { DataNode } from "antd/es/tree";
import { ItemType } from "antd/es/menu/interface";
import { validteUserAppTree } from "../../../serve/validators/tree";
import { readFileAsText } from "../../utils/common";

const isSSL = window.location.protocol === "https:";

interface EditorTreeProps {
    selectKey: number;
    navigate: NavigateFunction
    app: UserApp;
    detail: UserAppDetail;
    onChange: (detail: UserAppDetail) => void;
}

export default function EditorTree(props: EditorTreeProps) {
    const { app, detail, onChange, navigate, selectKey } = props;

    if (!app || !detail) {
        return <div className="text-center p-10">
            <Spin size="large" />
        </div>
    }

    const [keyword, setKeyword] = useState<string>("");
    const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
    const [process_init, setProcessInit] = useState(false);
    const [init_percent, setInitPercent] = useState({ total: 0, current: 0 });
    const toggleExpandedKeys = (key: React.Key) => {
        setExpandedKeys(expandedKeys => {
            const index = expandedKeys.indexOf(key);
            if (index === -1) {
                return [...expandedKeys, key];
            } else {
                return expandedKeys.filter(item => item !== key);
            }
        });
    }

    const importDoc = useMemo(() => {
        let index = 0
        return async (_: File, files: File[], parentId?: number) => {
            if (++index < files.length) {
                return false
            }
            for (let i = 0; i < files.length; i++) {
                const f = files[i];
                const name = f.name.replace(/\.[^.]+$/, "")
                const res_dir = await apis.save_dir({
                    app_id: app.id,
                    item: { id: undefined, title: name, parentId },
                })
                if (res_dir.success) {
                    const content = await readFileAsText(f)
                    const res_doc = await apis.save_doc({
                        app_id: app.id,
                        item_id: res_dir.data.item.id,
                        parent_id: parentId,
                        content,
                    })
                    if (res_doc.success) {
                        onChange(res_doc.data.detail);
                    } else {
                        message.error(res_doc.message);
                        return false
                    }
                } else {
                    message.error(res_dir.message)
                    return false
                }
            }
            return false
        }
    }, [app.id, detail])

    const importDir = useMemo(() => {
        let index = 0
        return async (_: File, files: File[]) => {
            if (++index < files.length) {
                return false
            }
            setProcessInit(true)

            const paths = files.map(f => f.webkitRelativePath)
            const res = await apis.app_init({ id: app.id, paths })
            if (res.success) {
                const { detail, path_map } = res.data
                onChange(detail)
                for (let j = 0; j < files.length; j++) {
                    const file = files[j];
                    const content = await readFileAsText(file)
                    if (content) {
                        const item_id = path_map[file.webkitRelativePath]
                        const parent_id = path_map[file.webkitRelativePath.split('/').slice(0, -1).join('/')]
                        const res_doc = await apis.save_doc({
                            app_id: app.id,
                            item_id,
                            parent_id,
                            content,
                        })
                        if (res_doc.success) {
                            onChange(res_doc.data.detail)
                            setInitPercent({
                                total: files.length,
                                current: j + 1
                            })
                        } else {
                            message.error(res_doc.message)
                            return false
                        }
                    }
                }
                setProcessInit(false)
            } else {
                message.error(res.message)
            }
            return false
        }
    }, [app.id])

    const [treeData, treeDataResult] = useMemo(() => {
        const treeData = mapTreeData(detail?.tree, {
            key: "id",
            title: "title",
            label: "title",
            parent_key: "parentId",
            __with_pinyin__: true,
            __with_rest__: true,
        })
        const expandedKeys: React.Key[] = []
        treeData[1].forEach(item => {
            const node = item as DataNode
            const item_id = Number(item.key)
            const items: ItemType[] = [
                {
                    key: "edit",
                    label: <ModalTreeNode btn="修改基本信息" app={app} item_id={item_id} detail={detail} onChange={({ detail }) => onChange(detail)} />,
                },
                {
                    key: "append",
                    label: <ModalTreeNode btn="新建下级文档" app={app} detail={detail} onChange={({ detail, item }) => {
                        onChange(detail)
                        navigate(`/app/${app.id}/${item.id}`)
                    }} parentId={item_id} />,
                },
                {
                    key: "import_markdown",
                    label: <Upload accept=".md" multiple showUploadList={false} beforeUpload={(file, files) => importDoc(file, files, item_id)}>
                        <Tooltip title="选择md文件上传到当前目录，支持多选" placement="right">
                            <span>上传文档</span>
                        </Tooltip>
                    </Upload>
                },
            ]
            const isLeaf = !item.children?.length
            if (isLeaf) {
                delete node.children;
                node.isLeaf = true;
                items.push({
                    key: "delete",
                    label: <Popconfirm title="确定删除吗？" onConfirm={() => {
                        apis.delete_dir({ app_id: app.id, item_id: Number(node.key) }).then(res => {
                            if (res.success) {
                                onChange(res.data);
                            } else {
                                message.error(res.message);
                            }
                        })
                    }}>
                        <span>删除当前文档</span>
                    </Popconfirm>,
                })
            } else {
                if (app.hideParent) {
                    node.selectable = false
                }
                expandedKeys.push(item.key)
            }
            if (node.selectable != false) {
                items.push({
                    key: 'copy',
                    label: <Typography.Text copyable={{
                        icon: [
                            <span className="text-black">复制链接</span>,
                            <span className="text-green-500">已复制</span>
                        ],
                        tooltips: "复制链接可用于嵌入正在编辑的文档",
                        text: `[${item.title}](${item.key})`
                    }} onClick={e => e.stopPropagation()} />,
                })
            }
            node.title = <div className="relative group" onClick={e => !isLeaf && app.hideParent && toggleExpandedKeys(item.key)}>
                <span>{item.title}</span>
                <Dropdown menu={{ items, onClick: e => e.domEvent.stopPropagation() }}>
                    <MoreOutlined className="absolute right-1 bottom-2 invisible group-hover:visible" />
                </Dropdown>
            </div>;
        })
        setExpandedKeys(expandedKeys)
        return [
            treeData,
            searchTreeData(keyword, treeData),
        ]
    }, [detail, keyword,]);

    const onSelect: TreeProps["onSelect"] = (selectedKeys) => {
        const [item_id] = selectedKeys as [number];
        if (item_id) {
            navigate(`/app/${app.id}/${item_id}`)
        }
    };

    const onDrop: TreeProps["onDrop"] = async (info) => {
        const { dragNode, node, dropToGap, dropPosition } = info;
        const item_id = dragNode.key as number;
        const parent_id = (dropToGap ? node["parent_key"] : node.key) as number;
        const position = dropToGap ? (dropPosition > 0 ? "after" : "before") : "inside";
        const anchor_id = (position === "inside" ? undefined : node.key) as number;
        const item = detail.tree.find(item => item.id === item_id);
        const error = validteUserAppTree({
            ...item, parentId: parent_id,
        }, detail)
        if (error) {
            message.error(error + ', 移动失败');
            return;
        }
        const res = await apis.move_dir({ app_id: app.id, item_id, parent_id, anchor_id, position });
        if (res.success) {
            onChange(res.data);
        } else {
            message.error(res.message);
        }
    };

    const isEmpty = !(treeData?.[0]?.length > 0)
    return <>
        <Spin spinning={process_init}>
            <div className="p-2">
                <h2 className="text-base overflow-hidden relative">
                    <b>{app?.title}</b>
                    <Dropdown menu={{
                        items: [
                            !isEmpty && {
                                key: "preview",
                                label: <a href={`/preview/${app.id}/?id=${selectKey}`} target="_blank" >预览站点</a>,
                            },
                            !isEmpty && {
                                key: "2",
                                label: <a href={`/export/${app.id}?t=${Date.now()}`} target="_blank">导出站点</a>
                            },
                            {
                                key: "3",
                                label: <Upload accept=".md" multiple showUploadList={false} beforeUpload={(file, files) => importDoc(file, files)}>
                                    <Tooltip title="选择md文件上传到根目录，支持多选" placement="right">
                                        上传文档
                                    </Tooltip>
                                </Upload>
                            },
                        ]
                    }} placement="bottomRight">
                        <Button type="link" size="small" icon={<MoreOutlined />} className="absolute -right-1 top-0" />
                    </Dropdown>
                </h2>
                <div className="text-center mt-4">
                    <ModalTreeNode btn={
                        <Tooltip title="快速新建文档">
                            <Button type="link" icon={<PlusOutlined />}>新建文档</Button>
                        </Tooltip>
                    } app={app} detail={detail} onChange={({ detail, item }) => {
                        onChange(detail)
                        navigate(`/app/${app.id}/${item.id}`)
                    }} />
                </div>

                {isEmpty ? (<div className="text-center text-gray-400">
                    <p>或</p>
                    <Upload accept=".zip" showUploadList={false} beforeUpload={async (info) => {
                        api_import(app.id, info).then(res => {
                            if (res.success) {
                                message.success("导入成功")
                                onChange(res.data)
                            } else {
                                message.error(res.message)
                            }
                        })
                        return false
                    }}>
                        <Tooltip title="使用 “导出站点” 文件进行导入，方便快速恢复数据">
                            <Button type="link" icon={<UploadOutlined />}>导入站点</Button>
                        </Tooltip>
                    </Upload>
                    {isSSL && <>
                        <p>或</p>
                        <Upload accept=".md" multiple showUploadList={false} directory beforeUpload={(file, files) => importDir(file, files)}>
                            <Tooltip title="支持打开本地目录，按照目录结构上传所有md文件，方便快速导入文档">
                                <Button type="link" icon={<UploadOutlined />}>上传目录</Button>
                            </Tooltip>
                        </Upload>
                    </>}
                </div>) : <Input placeholder="请输入文档名称搜索"
                    className="my-2"
                    onInput={(e) => setKeyword(e.currentTarget.value)}
                />}
                <Tree
                    className="overflow-auto md:max-h-[calc(100vh-208px)]"
                    selectedKeys={selectKey ? [selectKey] : []}
                    expandedKeys={expandedKeys}
                    onExpand={(expandedKeys) => setExpandedKeys(expandedKeys)}
                    draggable={{ icon: false }}
                    treeData={treeDataResult}
                    blockNode
                    onSelect={onSelect}
                    onDrop={onDrop}
                    switcherIcon={<CaretDownOutlined style={{ verticalAlign: "0.125em" }} />}
                />
            </div>
        </Spin>
        {process_init && init_percent.total > 0 && <div className="fixed left-0 right-0 top-0 bottom-0 text-center pt-60 z-50 bg-opacity-20 bg-gray-600">
            <Progress percent={Math.floor(init_percent.current * 100 / init_percent.total)} type="circle" strokeWidth={10} />
        </div>}
    </>;
}